﻿// <copyright file="EmailAddressHelper.cs" company="http://www.dymetis.com">
//
// Copyright (c) 2011 Eddie Z. Lin.
//
// This source is subject to the Microsoft Public License.
// See http://www.opensource.org/licenses/ms-pl.
// All other rights reserved.
// 
// </copyright>

namespace Dymetis.TeamAlert
{
    using System.Collections.Generic;
    using System.DirectoryServices.AccountManagement;
    using System.Linq;
    using System.Xml.Linq;
    using System.Xml.XPath;
    using Microsoft.TeamFoundation.Framework.Common;
    using Microsoft.TeamFoundation.Framework.Server;

    internal sealed class EmailAddressHelper
    {
        private readonly TeamFoundationRequestContext requestContext;

        private TeamFoundationIdentityService identityService;

        public EmailAddressHelper(TeamFoundationRequestContext requestContext)
        {
            this.requestContext = requestContext;
        }

        public IList<AlertRecipient> FindByDispalyName(XElement eventDocument, string fieldPath)
        {
            var addresses = new List<AlertRecipient>();

            var identityService = this.identityService ?? (this.identityService = this.requestContext.GetService<TeamFoundationIdentityService>());

            foreach (var displayName in eventDocument.XPathSelectElements(fieldPath).Select(e => e.Value))
            {
                var userIdentity = identityService.ReadIdentity(this.requestContext, IdentitySearchFactor.DisplayName, displayName, MembershipQuery.None, ReadIdentityOptions.None);

                var email = this.GetEmailAddress(userIdentity);
                if (email != null)
                {
                    addresses.Add(email);
                }
            }

            return addresses;
        }

        public IList<AlertRecipient> FindByAccountName(XElement eventDocument, string fieldPath)
        {
            var addresses = new List<AlertRecipient>();

            var identityService = this.identityService ?? (this.identityService = this.requestContext.GetService<TeamFoundationIdentityService>());

            foreach (var accountName in eventDocument.XPathSelectElements(fieldPath).Select(e => e.Value))
            {
                var userIdentity = identityService.ReadIdentity(this.requestContext, IdentitySearchFactor.AccountName, accountName, MembershipQuery.None, ReadIdentityOptions.None);

                var email = this.GetEmailAddress(userIdentity);
                if (email != null)
                {
                    addresses.Add(email);
                }
            }

            return addresses;
        }

        public IList<AlertRecipient> FindBySid(XElement eventDocument, string fieldPath)
        {
            var addresses = new List<AlertRecipient>();

            var identityService = this.identityService ?? (this.identityService = this.requestContext.GetService<TeamFoundationIdentityService>());

            foreach (var sid in eventDocument.XPathSelectElements(fieldPath).Select(e => e.Value))
            {
                var identity = IdentityHelper.CreateDescriptorFromSid(sid);
                var userIdentity = identityService.ReadIdentity(this.requestContext, identity, MembershipQuery.None, ReadIdentityOptions.None);

                var email = this.GetEmailAddress(userIdentity);
                if (email != null)
                {
                    addresses.Add(email);
                }
            }

            return addresses;
        }

        private AlertRecipient GetEmailAddress(TeamFoundationIdentity identity)
        {
            var domainName = IdentityHelper.GetDomainName(identity);

            using (var context = new PrincipalContext(ContextType.Domain, domainName))
            {
                var userPrincipal = UserPrincipal.FindByIdentity(context, System.DirectoryServices.AccountManagement.IdentityType.Sid, identity.Descriptor.Identifier);

                if (userPrincipal == null)
                {
                    return null;
                }

                return new AlertRecipient()
                {
                    EmailAddress = userPrincipal.EmailAddress,
                    DisplayName = userPrincipal.DisplayName
                };
            }
        }
    }
}
